OpenRoads Designer CONNECT Edition SDK Help

Terrain intersection

Description

  • This is a custom interactive tool for terrain and smart line intersection.

  • The user is prompted for line selection which user needs to select from UI from 3D view.

  • After line selection, this tool uses active terrain surface to find the intersection between terrain and line.

  • The TerrainIntersection class which extends DgnElementSetTool which handles different events to interact with UI, the TerrainIntersection class overrides the events here in this tool.

  • The method OnDataButton() handles the line selection from 3D view.

Remarks

  • This sample code is a part of ManagedSDKExample which you get with SDK installation under "examples" section in SDK installation directory.

  • If you encounter any error while using DgnElementSetTool class, make sure to add a reference to Bentley.DgnDisplayNet.dll by selecting Project > Add Reference or change the projects.csproj file to add reference to this dll .

  • The default dll location will be "C:\Program Files\Bentley\OpenRoads Designer CE 10.11\OpenRoadsDesigner\Bentley.DgnDisplayNet.dll".

Source Code


using System.Collections.Generic;
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.Elements;
using Bentley.CifNET.GeometryModel.SDK;
using Bentley.CifNET.SDK;
using Bentley.CifNET.LinearGeometry;

namespace ManagedSDKExample
{
    class TerrainIntersection : DgnElementSetTool
    {
        ConsensusConnection m_con;

        public TerrainIntersection() : base()
        {
        }

        protected override void OnRestartTool()
        {
            InstallNewInstance();
        }

        protected override void ExitTool()
        {
            if (m_con != null)
            {
                m_con.Close();
                m_con.Dispose();
            }
            m_con = null;
            base.ExitTool();
        }
	protected override void OnPostInstall()
        {
            base.BeginPickElements();
            m_con = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive();
            if (m_con == null)
                return;
            base.OnPostInstall();
            NotificationManager.OutputPrompt("Select SmartLine from 3D view");
        }

	//Select line from 3D view
        protected override bool OnDataButton(Bentley.DgnPlatformNET.DgnButtonEvent ev)
        {
            Bentley.DgnPlatformNET.HitPath hitPath = DoLocate(ev, true, 1);
            if (hitPath == null)
                return false;

            Element el = hitPath.GetCursorElement();

            if (el == null)
                return false;

            if (el.ElementType == MSElementType.LineString)
                TerrainAndLineIntersection(el);
            else
                return false;
           
            return true;
        }

        public override Bentley.DgnPlatformNET.StatusInt OnElementModify(Bentley.DgnPlatformNET.Elements.Element element)
        {
            return Bentley.DgnPlatformNET.StatusInt.Error;
        }

        protected override bool OnResetButton(Bentley.DgnPlatformNET.DgnButtonEvent ev)
        {
            ExitTool();
            return true;
        }

        public static void InstallNewInstance()
        {
            TerrainIntersection tool = new TerrainIntersection();
            tool.InstallTool();
        }

        public bool IntersectVector(Bentley.TerrainModelNET.DTM dtm, out Bentley.GeometryNET.DSegment3d intersectionSegment, Bentley.GeometryNET.DPoint3d startPt, Bentley.GeometryNET.DPoint3d endPt)
        {
            intersectionSegment = new Bentley.GeometryNET.DSegment3d();
            //Project the start and end points of line to terrain surface
            var drapeResult = dtm.DrapeLinearPoints(new Bentley.GeometryNET.DPoint3d[] { startPt, endPt });
            double vectorDist = startPt.DistanceXY(endPt);
            double vectorZDiff = endPt.Z - startPt.Z;
            bool hasPrevPt = false;
            Bentley.GeometryNET.DPoint3d prevPt = new Bentley.GeometryNET.DPoint3d();
            double prevZ = 0;
            bool prevAbove = false;
            foreach (var drapePt in drapeResult)
            {
                //Check Drapped point position i.e., inside terrain or outside terrain boundry
                if (drapePt.Code == Bentley.TerrainModelNET.DTMDrapedLinearElementPointCode.External || drapePt.Code == Bentley.TerrainModelNET.DTMDrapedLinearElementPointCode.Void)
                {
                    hasPrevPt = false;
                    continue;
                }

                Bentley.GeometryNET.DPoint3d newPt = drapePt.Coordinates;
                double newZ = startPt.Z + (drapePt.DistanceAlong / vectorDist) * vectorZDiff;
                bool newAbove = newZ > newPt.Z;
                if (hasPrevPt)
                {
                    if (newAbove != prevAbove)
                    {
                        //Create line segment from start point and end point of line
                        Bentley.GeometryNET.DSegment3d seg1 = new Bentley.GeometryNET.DSegment3d(startPt, endPt);
                        //Create line from drapped points from start point and end point on terrain
                        Bentley.GeometryNET.DSegment3d seg2 = new Bentley.GeometryNET.DSegment3d(prevPt, newPt);

                        double f1, f2;
                        //intersect both line segment and terrain segment
                        Bentley.GeometryNET.DSegment3d.ClosestApproachSegment(seg1, seg2, out intersectionSegment, out f1, out f2);

                        //Get intersection point from intersection line 
                        Bentley.GeometryNET.DPoint3d intersectPt = intersectionSegment.StartPoint;
                        return true;
                    }
                }

                hasPrevPt = true;
                prevPt = drapePt.Coordinates;
                prevZ = newZ;
                prevAbove = newAbove;
            }
            return false;
        }


        public void TerrainAndLineIntersection(Element el)
        {
            //Get active connection of dgn model  
            ConsensusConnection sdkCon = Bentley.CifNET.SDK.Edit.ConsensusConnectionEdit.GetActive();
            if (sdkCon == null)
                return;

            //Get geometric model
            GeometricModel geomModel = sdkCon.GetActiveGeometricModel();
            if (geomModel == null)
                return;

            SurfaceEntity activeSurface = geomModel.ActiveSurface;


            //Validate terrain surface and selected element
            if (activeSurface != null && activeSurface is TerrainSurface && el.ElementType == MSElementType.LineString)
            {
                TerrainSurface surface = activeSurface as TerrainSurface;
                List<LinearElement> segments = new List<LinearElement>();

                //Get active Dgn model
                DgnModel activeModel = Bentley.MstnPlatformNET.Session.Instance.GetActiveDgnModel();

                //Get model info to get units 
                ModelInfo info = activeModel.GetModelInfo();

                //Convert Element to LineString 
                Bentley.DgnPlatformNET.Elements.LineStringElement lineString = el as Bentley.DgnPlatformNET.Elements.LineStringElement;
                List<Bentley.GeometryNET.DPoint3d> pointList = new List<Bentley.GeometryNET.DPoint3d>();
                Bentley.GeometryNET.CurvePrimitive curvePrim = lineString.GetCurveVector().GetPrimitive(0);
                curvePrim.TryGetLineString(pointList);

                //Get LineString points 
                for (int i = 0; i < pointList.Count - 1; i++)
                {
                    Bentley.GeometryNET.DPoint3d point1 = pointList[i];
                    Bentley.GeometryNET.DPoint3d point2 = pointList[i + 1];
                    //Convert units to meter
                    point1.Set(point1.X / info.UorPerMeter, point1.Y / info.UorPerMeter, point1.Z / info.UorPerMeter);
                    point2.Set(point2.X / info.UorPerMeter, point2.Y / info.UorPerMeter, point2.Z / info.UorPerMeter);
                    //Create linear elements after converting units  
                    segments.Add(new Line3d(point1, point2));
                }

                //For each linear element find intersection of it with terrain 
                foreach (LinearElement le in segments)
                {
                    //Get intersecting line here
                    Bentley.GeometryNET.DSegment3d intersectLine = new Bentley.GeometryNET.DSegment3d();
                    bool intersects = IntersectVector(surface.DTM, out intersectLine, le.StartPoint.Coordinates, le.EndPoint.Coordinates);

                }
            }
        }

    }
}